import type { VarInit } from "~/models/data/var_init";
import type { Graph } from "../graph";
import { PNodeType } from "./type";
import { PSlot } from "../slot/prototype";
import { PSlotType } from "../slot/type";
import type { IDeserializable } from "~/models/serialize/IDeserializable";
import type { TypeTemplate } from "~/models/types/type_template";

interface PNodeInit {
  type?: PNodeType
  name?: string
  title?: string
  slots?: PSlot[]
  processTemplate?: string // 当且仅当type = PNodeType.Process
  branchTemplate?: string // 当且仅当type = PNodeType.Process
  typeTemplates?: TypeTemplate[]
}

/**
 * Trainer Graph Prototype Node
 */
export class PNode implements IDeserializable {

  className: string = 'PNode'

  type: PNodeType
  name: string
  title: string
  slots: PSlot[]

  /**
   * 当且仅当type = PNodeType
   * ProcessProcess节点的行内模板
   **/
  processTemplate?: string // 

  /**
   * 当且仅当type = PNodeType.Process
   * Process节点的分支模板
   **/
  branchTemplate?: string

  /** 泛型模板 */
  typeTemplates: TypeTemplate[]


  constructor(
    init?: PNodeInit
  ) {
    this.type = init?.type ?? PNodeType.None
    this.name = init?.name ?? ''
    this.title = init?.title ?? ''
    this.slots = init?.slots ?? []
    this.processTemplate = init?.processTemplate
    this.branchTemplate = init?.branchTemplate
    this.typeTemplates = init?.typeTemplates ?? []
  }

  public static readonly Process = {
    Start: new PNode({
      type: PNodeType.Process,
      name: 'Start',
      title: '开始',
      slots: [ PSlot.Preset.ProcessOut ],
    }),
    End: new PNode({
      type: PNodeType.Process,
      name: 'End',
      title: '结束',
      slots: [ PSlot.Preset.ProcessIn ],
    }),
  }

  same(that: PNode): boolean {
    return (
      this.name === that.name
      && this.title === that.title
      && this.type === that.type
      && this.slots.every((item, i) => item.same(that.slots[i]))
    )
  }

  /**
   * 创建
   */

  static getterFromTGD(tgdata: VarInit): PNode {
    return new PNode({
      type: PNodeType.Getter,
      name: tgdata.name,
      title: tgdata.name,
      slots: [ PSlot.OutData(tgdata.name, '', tgdata.type) ],
    })
  }

  static setterFromTGD(tgdata: VarInit): PNode {
    return new PNode({
      type: PNodeType.Setter,
      name: tgdata.name,
      title: tgdata.name,
      slots: [
        PSlot.Preset.ProcessIn,
        PSlot.Preset.ProcessOut,
        PSlot.InData(tgdata.name, tgdata.name, tgdata.type)
      ],
    })
  }

  static globalSetterFromTGD(tgdata: VarInit): PNode {
    return new PNode({
      type: PNodeType.Setter,
      name: `global_${tgdata.name}`,
      title: tgdata.name,
      slots: [
        PSlot.Preset.ProcessIn,
        PSlot.Preset.ProcessOut,
        PSlot.InData(tgdata.name, tgdata.name, tgdata.type)
      ],
    })
  }

  static funcFromGraph(graph: Graph): PNode {
    return new PNode({
      type: PNodeType.Function,
      name: graph.name,
      title: graph.name,
      slots: [
        PSlot.Preset.ProcessIn,
        PSlot.Preset.ProcessOut,
        ...graph.params,
        ...graph.returns,
      ],
    })
  }

  toString() {
    if (this.type === PNodeType.Function) {
      const paramStr = this.slots.length === 0 ? '无参数' : this.slots.filter(s => s.type === PSlotType.Data && s.direction === 'in').map(x => x.title).join(', ')
      return `${this.title}(${paramStr})`
      // {{ item.title }} {{ item.slots.length ? `(${item.slots.filter(s => s.type === PSlotType.Data && s.direction === 'in').map(x => x.title).join(', ')})` : undefined }}
    }
    else {
      return this.title
    }
  }
}
